<?php
// +----------------------------------------------------------------------
// | ThinkPHP
// +----------------------------------------------------------------------
// | Copyright (c) 2008 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
// $Id$

/**
 +------------------------------------------------------------------------------
 * ThinkPHP 数据库中间层实现类
 * 支持Mysql、MsSQL、Sqlite、Oracle、PgSQL等多种数据库
 * 还可以使用PDO
 +------------------------------------------------------------------------------
 * @category   Think
 * @package  Think
 * @subpackage  Db
 * @author    liu21st <liu21st@gmail.com>
 * @version   $Id$
 +------------------------------------------------------------------------------
 */
class Db extends Base
{

    const DB_READ_OPERATE       =       0;
    const DB_WRITE_OPERATE  =       1;

    // 数据库类型
    protected $dbType           = null;

    // 数据库版本
    protected $dbVersion            = null;

    // 当前数据库名称
    protected $dbName           =   null;
    // 是否自动释放查询结果
    protected $autoFree         = false;

    // 是否自动提交查询
    protected $autoCommit       = true;

    // 是否显示调试信息 如果启用会在日志文件记录sql语句
    protected $debug                = false;

    // 是否使用永久连接
    protected $pconnect         = false;

    // 当前SQL指令
    protected $queryStr         = '';

    // 当前结果
    protected $result               = null;

    // 当前查询的结果数据集
    protected $resultSet            = null;

    // 数据集返回类型 0 返回数组 1 返回对象
    public $resultType              = DATA_TYPE_ARRAY;

    // 当前查询返回的字段集
    protected $fields               = null;

    // 最后插入ID
    protected $lastInsID = null;

    // 返回或者影响记录数
    protected $numRows = 0;

    // 事务指令数
    protected $transTimes = 0;

    // 错误信息
    protected $error = '';

    // 数据库连接ID 支持多个连接
    protected $linkID  = array();

    // 当前连接ID
    protected $_linkID  =   null;

    // 当前查询ID
    protected $queryID = null;

    // 是否已经连接数据库
    protected $connected = false;

    // 数据库连接参数配置
    protected $config = '';

    // 数据库表达式
    protected $comparison = array('eq'=>'=','neq'=>'!=','gt'=>'>','egt'=>'>=','lt'=>'<','elt'=>'<=','like'=>'LIKE','between'=>'BETWEEN','notnull'=>'IS NOT NULL','null'=>'IS NULL');

    // SQL 执行时间记录
    protected $beginTime;

    /**
     +----------------------------------------------------------
     * 架构函数
     +----------------------------------------------------------
     * @access public
     +----------------------------------------------------------
     * @param array $config 数据库配置数组
     +----------------------------------------------------------
     */
    function __construct($config=''){
        return $this->factory($config);
    }

    /**
     +----------------------------------------------------------
     * 取得数据库类实例
     +----------------------------------------------------------
     * @static
     * @access public
     +----------------------------------------------------------
     * @return mixed 返回数据库驱动类
     +----------------------------------------------------------
     */
    public static function getInstance()
    {
        $args = func_get_args();
        return Think::instance(__CLASS__,'factory',$args);
    }

    /**
     +----------------------------------------------------------
     * 加载数据库 支持配置文件或者 DSN
     +----------------------------------------------------------
     * @access public
     +----------------------------------------------------------
     * @param mixed $db_config 数据库配置信息
     +----------------------------------------------------------
     * @return string
     +----------------------------------------------------------
     * @throws ThinkExecption
     +----------------------------------------------------------
     */
    public function &factory($db_config='')
    {
        // 读取数据库配置
        $db_config = $this->parseConfig($db_config);
        if(empty($db_config['dbms'])) {
            // 数据库配置信息错误
            throw_exception(L('_NO_DB_CONFIG_'));
        }
        // 数据库类型
        $this->dbType = ucwords(strtolower($db_config['dbms']));
        // 读取系统数据库驱动目录
        $dbClass = 'Db'. $this->dbType;
        $dbDriverPath = dirname(__FILE__).'/Driver/';
        require_cache( $dbDriverPath . $dbClass . '.class.php');

        // 检查驱动类
        if(class_exists($dbClass)) {
            $db = new $dbClass($db_config);
            // 获取当前的数据库类型
            if( 'pdo' != strtolower($db_config['dbms']) ) {
                $db->dbType = strtoupper($this->dbType);
            }else{
                $db->dbType = $this->_getDsnType($db_config['dsn']);
            }
        }else {
            // 类没有定义
            throw_exception(L('_NOT_SUPPORT_DB_').': ' . $db_config['dbms']);
        }
        return $db;
    }

    /**
     +----------------------------------------------------------
     * 根据DSN获取数据库类型 返回大写
     +----------------------------------------------------------
     * @access protected
     +----------------------------------------------------------
     * @param string $dsn  dsn字符串
     +----------------------------------------------------------
     * @return string
     +----------------------------------------------------------
     */
    protected function _getDsnType($dsn) {
        $match  =  explode(':',$dsn);
        $dbType = strtoupper(trim($match[0]));
        return $dbType;
    }

    /**
     +----------------------------------------------------------
     * 分析数据库配置信息，支持数组和DSN
     +----------------------------------------------------------
     * @access private
     +----------------------------------------------------------
     * @param mixed $db_config 数据库配置信息
     +----------------------------------------------------------
     * @return string
     +----------------------------------------------------------
     */
    private function parseConfig($db_config='') {
        if ( !empty($db_config) && is_string($db_config)) {
            // 如果DSN字符串则进行解析
            $db_config = $this->parseDSN($db_config);
        }else if(empty($db_config)){
            // 如果配置为空，读取配置文件设置
            $db_config = array (
                'dbms'     => C('DB_TYPE'),
                'username' => C('DB_USER'),
                'password' => C('DB_PWD'),
                'hostname' => C('DB_HOST'),
                'hostport' => C('DB_PORT'),
                'database' => C('DB_NAME'),
                'dsn'       =>  C('DB_DSN'),
                'params'=> C('DB_PARAMS'),
            );
        }
        return $db_config;
    }

    /**
     +----------------------------------------------------------
     * 初始化数据库连接
     +----------------------------------------------------------
     * @access protected
     +----------------------------------------------------------
     * @param integer $type 读写操作类型
     +----------------------------------------------------------
     * @return void
     +----------------------------------------------------------
     */
    protected function initConnect($type='') {
        if(1 == C('DB_DEPLOY_TYPE')) {
            // 采用分布式数据库
            $this->_linkID = $this->multiConnect($type);
        }else{
            // 默认单数据库
            if ( !$this->connected ) $this->_linkID = $this->connect();
        }
    }

    /**
     +----------------------------------------------------------
     * 增加数据库连接
     +----------------------------------------------------------
     * @access protected
     +----------------------------------------------------------
     * @param mixed $config 数据库连接信息
     * @param mixed $linkNum  创建的连接序号
     +----------------------------------------------------------
     * @return void
     +----------------------------------------------------------
     */
    public function addConnect($config,$linkNum=null) {
        $db_config  =   $this->parseConfig($config);
        if(empty($linkNum)) {
            $linkNum     =   count($this->linkID);
        }
        if(isset($this->linkID[$linkNum])) {
            // 已经存在连接
            return false;
        }
        // 创建新的数据库连接
        return $this->connect($db_config,$linkNum);
    }

    /**
     +----------------------------------------------------------
     * 切换数据库连接
     +----------------------------------------------------------
     * @access protected
     +----------------------------------------------------------
     * @param integer $linkNum  创建的连接序号
     +----------------------------------------------------------
     * @return void
     +----------------------------------------------------------
     */
    public function switchConnect($linkNum) {
        if(isset($this->linkID[$linkNum])) {
            // 存在指定的数据库连接序号
            $this->_linkID  =   $this->linkID[$linkNum];
            return true;
        }else{
            return false;
        }
    }

    /**
     +----------------------------------------------------------
     * 连接分布式服务器
     +----------------------------------------------------------
     * @access protected
     +----------------------------------------------------------
     * @param boolean $master 主服务器
     +----------------------------------------------------------
     * @return void
     +----------------------------------------------------------
     */
    protected function multiConnect($type='') {
        static $_config = array();
        if(empty($_config)) {
            // 缓存分布式数据库配置解析
            foreach ($this->config as $key=>$val){
                $_config[$key]      =   explode(',',$val);
            }
        }
        // 数据库读写是否分离
        if(C('DB_RW_SEPARATE')){
            // 主从式采用读写分离
            // 默认主服务器是连接第一个数据库配置
            if(self::DB_READ_OPERATE == $type) {
                // 读操作连接从服务器
                $no = floor(mt_rand(1,count($_config['hostname'])-1));  // 每次随机连接的数据库
            }else{
                $no =   0;
            }
        }else{
            // 读写操作不区分服务器
            $no = floor(mt_rand(0,count($_config['hostname'])-1));  // 每次随机连接的数据库
        }
        $db_config = array(
            'username'=>     isset($_config['username'][$no])?$_config['username'][$no]:$_config['username'][0],
            'password' => isset($_config['password'][$no])?$_config['password'][$no]:$_config['password'][0],
            'hostname' => isset($_config['hostname'][$no])?$_config['hostname'][$no]:$_config['hostname'][0],
            'hostport' =>    isset($_config['hostport'][$no])?$_config['hostport'][$no]:$_config['hostport'][0],
            'database' =>    isset($_config['database'][$no])?$_config['database'][$no]:$_config['database'][0],
            'dsn'   =>  isset($_config['dsn'][$no])?$_config['dsn'][$no]:$_config['dsn'][0],
            'params'    =>  isset($_config['params'][$no])?$_config['params'][$no]:$_config['params'][0],
        );
        return $this->connect($db_config,$no);
    }

    /**
     +----------------------------------------------------------
     * DSN解析
     * 格式： mysql://username:passwd@localhost:3306/DbName
     +----------------------------------------------------------
     * @static
     * @access public
     +----------------------------------------------------------
     * @param string $dsnStr
     +----------------------------------------------------------
     * @return array
     +----------------------------------------------------------
     */
    public function parseDSN($dsnStr)
    {
        if( empty($dsnStr) ){return false;}
        $info = parse_url($dsnStr);
        if($info['scheme']){
            $dsn = array(
            'dbms'     => $info['scheme'],
            'username' => $info['user'] ? $info['user'] : '',
            'password' => $info['pass'] ? $info['pass'] : '',
            'hostname' => $info['host'] ? $info['host'] : '',
            'hostport' => $info['port'] ? $info['port'] : '',
            'database' => $info['path'] ? substr($info['path'],1) : ''
            );
        }else {
            preg_match('/^(.*?)\:\/\/(.*?)\:(.*?)\@(.*?)\:([0-9]{1, 6})\/(.*?)$/',trim($dsnStr),$matches);
            $dsn = array (
            'dbms'     => $matches[1],
            'username' => $matches[2],
            'password' => $matches[3],
            'hostname' => $matches[4],
            'hostport' => $matches[5],
            'database' => $matches[6]
            );
        }
        return $dsn;
     }

    /**
     +----------------------------------------------------------
     * 数据库调试 记录当前SQL
     +----------------------------------------------------------
     * @access protected
     +----------------------------------------------------------
     */
    protected function debug() {
        if ( $this->debug || C('SQL_DEBUG_LOG')) {
            // 记录操作结束时间
            $runtime    =   number_format((microtime(TRUE) - $this->beginTime), 6);
            Log::record(" RunTime:".$runtime."s SQL = ".$this->queryStr,SQL_LOG_DEBUG);
        }
    }

    /**
     +----------------------------------------------------------
     * table分析
     +----------------------------------------------------------
     * @access public
     +----------------------------------------------------------
     * @param mixed $tables  数据表名
     +----------------------------------------------------------
     * @return string
     +----------------------------------------------------------
     */
    protected function parseTables($tables)
    {
        if(is_array($tables)) {
            if(0 === strpos($this->dbType,'MYSQL')) {
                array_walk($tables, array($this, 'addSpecialChar'));
            }
            $tablesStr = implode(',', $tables);
        }
        else if(is_string($tables)) {
            if(0 === strpos($this->dbType,'MYSQL') && false === strpos($tables,'`')) {
                $tablesStr =  '`'.trim($tables).'`';
            }else{
                $tablesStr = $tables;
            }
        }
        return $tablesStr;
    }

    /**
     +----------------------------------------------------------
     * where分析
     +----------------------------------------------------------
     * @access public
     +----------------------------------------------------------
     * @param mixed $where 查询条件
     +----------------------------------------------------------
     * @return string
     +----------------------------------------------------------
     */
    protected function parseWhere($where)
    {
        $whereStr = '';
        if(C('USE_STR_WHERE') && is_string($where) && !empty($where)) {
            // 支持直接使用字符串作为查询条件
            return ' WHERE '.$where;
        }
        if(is_object($where)){
            $where = get_object_vars($where);
        }elseif(is_string($where)){
            parse_str($where,$where);
        }
        if(!empty($where)) {
            if(array_key_exists('_string',$where)) {
                // 纯字符串条件表达式
                // 例如 $where = array('_string','a.id >= 1 AND b.id IN (1,2,3));
                return ' WHERE '.$where['_string'];
            }
            elseif(array_key_exists('_logic',$where)) {
                // 定义逻辑运算规则 例如 OR XOR AND NOT
                $operate    =   ' '.strtoupper($where['_logic']).' ';
                unset($where['_logic']);
            }else{
                // 默认进行 AND 运算
                $operate    =   ' AND ';
            }
            foreach ($where as $key=>$val){
                if(strpos($key,C('FIELDS_DEPR'))) {
                    $key    =   explode(',',$key);
                    if( 0 === strpos($this->dbType,'MYSQL')) {
                        array_walk($key, array($this, 'addSpecialChar'));
                    }
                }elseif( 0 === strpos($this->dbType,'MYSQL')) {
                    $key = $this->addSpecialChar($key);
                }
                $whereStr .= "( ";
                if(is_array($val)) {
                        if(is_array($key)) {
                            // 多字段组合查询
                            $num    =   count($key);
                            if(empty($val[$num])) $val[$num]    =   'AND'; // 运算规则默认为AND
                            for ($i=0;$i<$num;$i++){
                                if(is_array($val[$i])) {
                                    // 判断条件
                                    if(is_string($val[$i][0]) && preg_match('/^(EQ|NEQ|GT|EGT|LT|ELT|LIKE)F$/i',$val[$i][0])) {
                                        $op =   $this->comparison[strtolower(substr($val[$i][0],0,-1))];
                                        $str[] = ' ('.$key[$i].' '.$op.' '.$val[$i][1].') ';
                                    }elseif(is_string($val[$i][0]) && preg_match('/IN/i',$val[$i][0])){
                                        if(is_array($val[$i][1])) {
                                            array_walk($val[$i][1], array($this, 'fieldFormat'));
                                            $zone   =   implode(',',$val[$i][1]);
                                        }else{
                                            $zone   =   $val[$i][1];
                                        }
                                        $str[] =  ' ('.$key[$i].' '.strtoupper($val[$i][0]).' ('.$zone.') )';
                                    }elseif(is_string($val[$i][0]) && preg_match('/^(EQ|NEQ|GT|EGT|LT|ELT|LIKE|NULL|NOTNULL|BETWEEN)$/i',$val[$i][0])){
                                        $op =   $this->comparison[strtolower($val[$i][0])];
                                        $str[] = ' ('.$key[$i].' '.$op.' '.$this->fieldFormat($val[$i][1]).') ';
                                    }else{
                                        $str[] = ' ('.$key[$i].' '.$val[$i][0].' '.$this->fieldFormat($val[$i][1]).') ';
                                    }
                                }else{
                                    // 默认为 ＝
                                    $str[] = ' ('.$key[$i].' = '.$this->fieldFormat($val[$i]).') ';
                                }
                            }
                            $whereStr .= implode(strtoupper($val[$num]),$str);
                        }else{
                            if(is_string($val[0]) && preg_match('/^(EQ|NEQ|GT|EGT|LT|ELT|LIKE|NULL|NOTNULL|BETWEEN)$/i',$val[0])) {
                                // 是否存在比较运算
                                $whereStr .= $key.' '.$this->comparison[strtolower($val[0])].' '.$this->fieldFormat($val[1]);
                            }elseif(is_string($val[0]) && preg_match('/IN/i',$val[0])){
                                // 支持 IN 运算
                                if(is_array($val[1])) {
                                    array_walk($val[1], array($this, 'fieldFormat'));
                                    $zone   =   implode(',',$val[1]);
                                }else{
                                    $zone   =   $val[1];
                                }
                                $whereStr .= $key.' '.strtoupper($val[0]).' ('.$zone.')';
                            }elseif(is_string($val[0]) && preg_match('/^(EQ|NEQ|GT|EGT|LT|ELT|LIKE)F$/i',$val[0])){
                                $whereStr .= $key.' '.$this->comparison[strtolower(substr($val[0],0,-1))].' '.$val[1];
                            }else {
                                if(($count = count($val))>2) {
                                    if(in_array(strtoupper(trim($val[$count-1])),array('AND','OR','XOR'))) {
                                        $rule = strtoupper(trim($val[$count-1]));
                                        $count   =  $count -1;
                                    }else{
                                        $rule = 'AND';
                                    }
                                    for($i=0;$i<$count;$i++) {
                                        $op = is_array($val[$i])?$this->comparison[strtolower($val[$i][0])]:'=';
                                        $data = is_array($val[$i])?$val[$i][1]:$val[$i];
                                        $whereStr .= '('.$key.' '.$op.' '.$this->fieldFormat($data).') '.$rule.' ';
                                    }
                                    $whereStr = substr($whereStr,0,-4);
                                }else{
                                    // 区间比较只有两个段
                                    if(is_array($val[0])) {
                                        // 给出运算符
                                        $operate1   =   $this->comparison[strtolower($val[0][0])];
                                        $data1  =   $val[0][1];
                                    }else{
                                        // 默认的运算符
                                        $operate1   =   '>=';
                                        $data1  =   $val[0];
                                    }
                                    if(is_array($val[1])) {
                                        $operate2   =   $this->comparison[strtolower($val[1][0])];
                                        $data2  =   $val[1][1];
                                    }else{
                                        $operate2   =   '<=';
                                        $data2  =   $val[1];
                                    }
                                    if(empty($val[2])) $val[2]  =   'AND'; // 运算规则默认为AND
                                    if(in_array(strtoupper(trim($val[2])),array('AND','OR','XOR'))) {
                                        $whereStr .= $key.' '.$operate1.' '.$this->fieldFormat($data1).' '.$val[2].' '.$key.' '.$operate2.' '.$this->fieldFormat($data2);
                                    }
                                }
                            }
                        }
                }else {
                    //对字符串类型字段采用模糊匹配
                    if(C('LIKE_MATCH_FIELDS') && preg_match('/('.C('LIKE_MATCH_FIELDS').')/i',$key)) {
                        $val = '%'.$val.'%';
                        $whereStr .= $key." LIKE ".$this->fieldFormat($val);
                    }else {
                        $whereStr .= $key." = ".$this->fieldFormat($val);
                    }
                }
                $whereStr .= ' )'.$operate;
            }
            $whereStr = ' WHERE '.substr($whereStr,0,-strlen($operate));
        }
        return $whereStr;
    }

    /**
     +----------------------------------------------------------
     * order分析
     +----------------------------------------------------------
     * @access protected
     +----------------------------------------------------------
     * @param mixed $order 排序
     +----------------------------------------------------------
     * @return string
     +----------------------------------------------------------
     */
    protected function parseOrder($order)
    {
        $orderStr = '';
        if(is_array($order))
            $orderStr .= ' ORDER BY '.implode(',', $order);
        else if(is_string($order) && !empty($order))
            $orderStr .= ' ORDER BY '.$order;
        return $orderStr;
    }

    /**
     +----------------------------------------------------------
     * join分析
     +----------------------------------------------------------
     * @access protected
     +----------------------------------------------------------
     * @param mixed $join Join表达式
     +----------------------------------------------------------
     * @return string
     +----------------------------------------------------------
     */
    protected function parseJoin($join)
    {
        $joinStr = '';
        if(!empty($join)) {
            if(is_array($join)) {
                foreach ($join as $key=>$_join){
                    if(false !== stripos($_join,'JOIN')) {
                        $joinStr .= ' '.$_join;
                    }else{
                        $joinStr .= ' LEFT JOIN ' .$_join;
                    }
                }
            }else{
                $joinStr .= ' LEFT JOIN ' .$join;
            }
        }
        return $joinStr;
    }

    /**
     +----------------------------------------------------------
     * limit分析
     +----------------------------------------------------------
     * @access protected
     +----------------------------------------------------------
     * @param string $limit
     +----------------------------------------------------------
     * @return string
     +----------------------------------------------------------
     */
    protected function parseLimit($limit)
    {
        return !empty($limit)?$this->limit($limit):'';
    }

    /**
     +----------------------------------------------------------
     * group分析
     +----------------------------------------------------------
     * @access protected
     +----------------------------------------------------------
     * @param mixed $group
     +----------------------------------------------------------
     * @return string
     +----------------------------------------------------------
     */
    protected function parseGroup($group)
    {
        $groupStr = '';
        if(is_array($group))
            $groupStr .= ' GROUP BY '.implode(',', $group);
        else if(is_string($group) && !empty($group))
            $groupStr .= ' GROUP BY '.$group;
        return empty($groupStr)?'':$groupStr;
    }

    /**
     +----------------------------------------------------------
     * having分析
     +----------------------------------------------------------
     * @access protected
     +----------------------------------------------------------
     * @param string $having
     +----------------------------------------------------------
     * @return string
     +----------------------------------------------------------
     */
    protected function parseHaving($having)
    {
        $havingStr = '';
        if(is_string($having) && !empty($having))
            $havingStr .= ' HAVING '.$having;
        return $havingStr;
    }

    /**
     +----------------------------------------------------------
     * fields分析
     +----------------------------------------------------------
     * @access protected
     +----------------------------------------------------------
     * @param mixed $fields
     +----------------------------------------------------------
     * @return string
     +----------------------------------------------------------
     */
    protected function parseFields($fields)
    {
        if(is_array($fields)) {
            if(0 === strpos($this->dbType,'MYSQL')) {
                array_walk($fields, array($this, 'addSpecialChar'));
            }
            $fieldsStr = implode(',', $fields);
        }else if( !empty($fields) && is_string($fields)) {
            if( false === strpos($fields,'`') ) {
                $fields = explode(',',$fields);
                if( 0 === strpos($this->dbType,'MYSQL')) {
                    array_walk($fields, array($this, 'addSpecialChar'));
                }
                $fieldsStr = implode(',', $fields);
            }else {
                $fieldsStr = $fields;
            }
        }else
            $fieldsStr = '*';
        return $fieldsStr;
    }

    /**
     +----------------------------------------------------------
     * value分析
     +----------------------------------------------------------
     * @access protected
     +----------------------------------------------------------
     * @param mixed $values
     +----------------------------------------------------------
     * @return string
     +----------------------------------------------------------
     */
    protected function parseValues($values)
    {
        if(is_array($values)) {
            array_walk($values, array($this, 'fieldFormat'));
            $valuesStr = implode(',', $values);
        }
        else if(is_string($values))
            $valuesStr = $values;
        return $valuesStr;
    }

    /**
     +----------------------------------------------------------
     * set分析
     +----------------------------------------------------------
     * @access protected
     +----------------------------------------------------------
     * @param mixed $sets
     +----------------------------------------------------------
     * @return string
     +----------------------------------------------------------
     */
    protected function parseSets($sets)
    {
        $setsStr  = '';
        $sets    = auto_charset($sets,C('OUTPUT_CHARSET'),C('DB_CHARSET'));
        if(is_array($sets)){
            foreach ($sets as $key=>$val){
                if(0 === strpos($this->dbType,'MYSQL')) {
                    $key    =   $this->addSpecialChar($key);
                }
                if(is_array($val) && strtolower($val[0]) == 'exp') {
                    $val    =   $val[1];                        // 使用表达式
                }elseif(!is_null($val) && is_scalar($val)){
                    $val    =   $this->fieldFormat($val);
                }else{
                    // 过滤控制和复合对象
                    continue;
                }
                $setsStr .= trim($key) ."= ".$val.",";
            }
            $setsStr = substr($setsStr,0,-1);
        }else if(is_string($sets)) {
            $setsStr = $sets;
        }
        return ' SET '.$setsStr;
    }

    /**
     +----------------------------------------------------------
     * distinct分析
     +----------------------------------------------------------
     * @access protected
     +----------------------------------------------------------
     * @param boolean $distinct
     +----------------------------------------------------------
     * @return string
     +----------------------------------------------------------
     */
    protected function parseDistinct($distinct) {
        $parseStr   =   '';
        if($distinct) {
            $parseStr   .=  ' DISTINCT ';
        }
        return $parseStr;
    }

    /**
     +----------------------------------------------------------
     * table分析
     +----------------------------------------------------------
     * @access protected
     +----------------------------------------------------------
     * @param array|string $tables
     +----------------------------------------------------------
     * @return string
     +----------------------------------------------------------
     */
    protected function parseTable($tables) {
        $parseStr   =   '';
        if(is_string($tables)) {
            $tables  =  explode(',',$tables);
        }
        if( 0 === strpos($this->dbType,'MYSQL')) {
            array_walk($tables, array($this, 'addSpecialChar'));
        }
        $parseStr   =  implode(',',$tables);
        return $parseStr;
    }

    /**
     +----------------------------------------------------------
     * 设置锁机制
     +----------------------------------------------------------
     * @access protected
     +----------------------------------------------------------
     * @return string
     +----------------------------------------------------------
     */
    protected function setLockMode() {
        if('ORACLE' == $this->dbType || 'OCI'==$this->dbType) {
            return ' FOR UPDATE NOWAIT ';
        }
        return ' FOR UPDATE ';
    }

    /**
     +----------------------------------------------------------
     * 字段格式化
     +----------------------------------------------------------
     * @access protected
     +----------------------------------------------------------
     * @param mixed $value
     +----------------------------------------------------------
     * @return mixed
     +----------------------------------------------------------
     */
    public function fieldFormat(&$value)
    {
        if(is_int($value) || is_float($value)) {
            return $value;
        }elseif(preg_match('/^\((\s|\w)*(\+|\-|\*|\/)?(\s|\w)*\)$/i',$value)){
            // 支持在字段的值里面直接使用其它字段
            // 例如 (score+1) (name) 必须包含括号
            $value = $this->escape_string($value);
        }else if(is_string($value)) {
            $value = '\''.$this->escape_string($value).'\'';
        }
        return $value;
    }

    /**
     +----------------------------------------------------------
     * 字段和表名添加` 符合
     * 保证指令中使用关键字不出错 针对mysql
     +----------------------------------------------------------
     * @access protected
     +----------------------------------------------------------
     * @param mixed $value
     +----------------------------------------------------------
     * @return mixed
     +----------------------------------------------------------
     */
    protected function addSpecialChar(&$value)
    {
        if( '*' == $value ||  false !== strpos($value,'(') || false !== strpos($value,'.') || false !== strpos($value,'`')) {
            //如果包含* 或者 使用了sql方法 则不作处理
        }
        elseif(false === strpos($value,'`') ) {
            $value = '`'.trim($value).'`';
        }
        return $value;
    }

    /**
     +----------------------------------------------------------
     * 是否为数据库更改操作
     +----------------------------------------------------------
     * @access protected
     +----------------------------------------------------------
     * @param string $query  SQL指令
     +----------------------------------------------------------
     * @return boolen 如果是查询操作返回false
     +----------------------------------------------------------
     */
    public function isMainIps($query)
    {
        $queryIps = 'INSERT|UPDATE|DELETE|REPLACE|'
                . 'CREATE|DROP|'
                . 'LOAD DATA|SELECT .* INTO|COPY|'
                . 'ALTER|GRANT|REVOKE|'
                . 'LOCK|UNLOCK';
        if (preg_match('/^\s*"?(' . $queryIps . ')\s+/i', $query)) {
            return true;
        }
        return false;
    }

    /**
     +----------------------------------------------------------
     * 查询数据方法
     +----------------------------------------------------------
     * @access public
     +----------------------------------------------------------
     * @param string $sql  查询语句
     * @param array $options  表达式
     * @param boolean $returnSql 是否返回SQL
     +----------------------------------------------------------
     * @return mixed
     +----------------------------------------------------------
     */
    public function query($sql='',$options=array(),$returnSql=false)
    {
        if(empty($sql)) {
            $sql   = $this->queryStr;
        }
        if(isset($options['lock']) && $options['lock']) {
            $sql .= $this->setLockMode();
        }
        if(isset($options['lazy']) && $options['lazy']) {
            // 延时读取数据库
            return $this->lazyQuery($sql);
        }
        if($returnSql) {
            $this->queryStr = '';
            return $sql;
        }
        // 进行查询
        if($this->_query($sql)) {
            return $this->getAll();
        }else{
            return false;
        }
    }

    /**
     +----------------------------------------------------------
     * 延时查询方法
     +----------------------------------------------------------
     * @access public
     +----------------------------------------------------------
     * @param string $sql  查询语句
     +----------------------------------------------------------
     * @return ResultIterator
     +----------------------------------------------------------
     */
    public function lazyQuery($sql='') {
        // 返回ResultIterator对象 在操作数据的时候再进行读取
        Think::import("Think.Db.ResultIterator");
        return new ResultIterator($sql);
    }

    /**
     +----------------------------------------------------------
     * 数据库操作方法
     +----------------------------------------------------------
     * @access public
     +----------------------------------------------------------
     * @param string $sql  执行语句
     * @param array $options  表达式
     * @param boolean $returnSql 是否返回SQL
     +----------------------------------------------------------
     * @return void
     +----------------------------------------------------------
     */
    public function execute($sql='',$options=array(),$returnSql=false)
    {
        if(empty($sql)) {
            $sql  = $this->queryStr;
        }
        if(isset($options['lock']) && $options['lock']) {
            $sql .= $this->setLockMode();
        }
        if($returnSql) {
            $this->queryStr = '';
            return $sql;
        }
        return $this->_execute($sql);
    }

    /**
     +----------------------------------------------------------
     * 自动判断进行查询或者执行操作
     +----------------------------------------------------------
     * @access public
     +----------------------------------------------------------
     * @param string $sql SQL指令
     * @param array $options  表达式
     +----------------------------------------------------------
     * @return mixed
     +----------------------------------------------------------
     */
    public function autoExec($sql='',$options=array())
    {
        if(empty($sql)) {
            $sql  = $this->queryStr;
        }
        if($this->isMainIps($sql)) {
            $this->execute($sql,$options);
        }else {
            $this->query($sql,$options);
        }
    }

    /**
     +----------------------------------------------------------
     * 查找记录
     +----------------------------------------------------------
     * @access public
     +----------------------------------------------------------
     * @param array $options 查询表达式
     * 例如 array('condition'=>'id=1','field'=>'id,name','order'=>'id desc')
     * 支持下面的一些索引
     * condition 查询条件
     * table  数据表名
     * field  字段名
     * order  排序
     * limit
     * group
     * having
     * cache 是否缓存
     * lazy 是否惰性加载
     * lock 是否加锁
     * @param boolean $returnSql 是否返回SQL
     +----------------------------------------------------------
     * @return array
     +----------------------------------------------------------
     */
    public function select($options=array(),$returnSql=false)
    {
        $distinct   =   false;
        $field  =   $join   =   $group  =   $having =   $order  =   $limit  =   $condition  =   '';
        extract($options);
        switch($this->dbType) {
            case 'MSSQL':
            case 'IBASE':
            case 'FIREBIRD':
            case 'INTERBASE':
                $this->queryStr = 'SELECT '
                        .$this->parseDistinct($distinct)
                        .$this->parseLimit($limit)
                        .$this->parseFields($field)
                        .' FROM '.$this->parseTable($table)
                        .$this->parseJoin($join)
                        .$this->parseWhere($condition)
                        .$this->parseGroup($group)
                        .$this->parseHaving($having)
                        .$this->parseOrder($order);
                break;
            case 'ORACLE':
            case 'OCI':
                if($limit)
                {
                    $this->queryStr = "SELECT *	FROM (SELECT rownum AS numrow, thinkphp.* FROM (SELECT "
                        .$this->parseDistinct($distinct)
                        .$this->parseFields($fields)
                        ." FROM ".$this->parseTable($table)
                        .$this->parseJoin($join)
                        .$this->parseWhere($where)
                        .$this->parseGroup($group)
                        .$this->parseHaving($having)
                        .$this->parseOrder($order)
                        .") thinkphp) WHERE "
                        .$this->parseLimit($limit);
                }
                else
                {
                    $this->queryStr = 'SELECT '
                        .$this->parseDistinct($distinct)
                        .$this->parseFields($fields)
                        .' FROM '.$this->parseTable($table)
                        .$this->parseJoin($join)
                        .$this->parseWhere($where)
                        .$this->parseGroup($group)
                        .$this->parseHaving($having)
                        .$this->parseOrder($order);
                }
                break;
            case 'MYSQL':
            case 'MYSQLI':
            default:
                $this->queryStr = 'SELECT '
                        .$this->parseDistinct($distinct)
                        .$this->parseFields($field)
                        .' FROM '.$this->parseTable($table)
                        .$this->parseJoin($join)
                        .$this->parseWhere($condition)
                        .$this->parseGroup($group)
                        .$this->parseHaving($having)
                        .$this->parseOrder($order)
                        .$this->parseLimit($limit);
        }
        return $this->query($this->queryStr,$options,$returnSql);
    }

    /**
     +----------------------------------------------------------
     * 插入记录
     +----------------------------------------------------------
     * @access public
     +----------------------------------------------------------
     * @param mixed $data 数据
     * @param array $options  参数列表
     * @param boolean $returnSql 是否返回SQL
     +----------------------------------------------------------
     * @return false | integer
     +----------------------------------------------------------
     * @throws ThinkExecption
     +----------------------------------------------------------
     */
    public function insert($map,$options=array(),$returnSql=false)
    {
        extract($options);
        if(!is_array($map)) {
            throw_exception(L('_DATA_TYPE_INVALID_'));
        }
        // 去掉复合对象 保证关联数据属性不会被保存导致错误
        foreach ($map as $key=>$val){
            if(is_array($val) && strtolower($val[0]) == 'exp') {
                $val    =   $val[1];                        // 使用表达式
            }elseif (is_scalar($val)){
                $val    =   $this->fieldFormat($val);
            }else{
                // 去掉复合对象
                continue;
            }
            $data[trim($key)]   =   $val;
        }
        //转换数据库编码
        $data    = auto_charset($data,C('OUTPUT_CHARSET'),C('DB_CHARSET'));
        $fields = array_keys($data);
        if( 0 === strpos($this->dbType,'MYSQL')) {
            array_walk($fields, array($this, 'addSpecialChar'));
        }
        $fieldsStr = implode(',', $fields);
        $values = array_values($data);
        //array_walk($values, array($this, 'fieldFormat'));

        $valuesStr = implode(',', $values);
        $this->queryStr =    'INSERT INTO '.$this->parseTable($table).' ('.$fieldsStr.') VALUES ('.$valuesStr.')';
        return $this->execute($this->queryStr,$options,$returnSql);
    }

    /**
     +----------------------------------------------------------
     * 通过Select方式插入记录
     +----------------------------------------------------------
     * @access public
     +----------------------------------------------------------
     * @param array $insertOptions 插入数据参数
     * @param array $selectOption  查询数据参数
     * @param boolean $returnSql 是否返回SQL
     +----------------------------------------------------------
     * @return false | integer
     +----------------------------------------------------------
     */
    public function selectInsert($insertOptions=array(),$selectOptions=array(),$returnSql=false) {
        $fields =   $insertOptions['field'];
        $table      =   $insertOptions['table'];
        $this->queryStr =    'INSERT INTO '.$this->parseTable($table).' ('.$fields.') ';
        extract($selectOptions);
        $selectStr   = 'SELECT '.$this->parseFields($field)
                                    .' FROM '.$this->parseTable($table)
                                    .$this->parseJoin($join)
                                    .$this->parseWhere($condition)
                                    .$this->parseGroup($group)
                                    .$this->parseHaving($having)
                                    .$this->parseOrder($order)
                                    .$this->parseLimit($limit);
        $this->queryStr .= $selectStr;
        return $this->execute($this->queryStr,$returnSql);
    }

    /**
     +----------------------------------------------------------
     * 删除记录
     +----------------------------------------------------------
     * @access public
     +----------------------------------------------------------
     * @param array $options  删除参数
     +----------------------------------------------------------
     * @return false | integer
     +----------------------------------------------------------
     */
    public function delete($options=array(),$returnSql=false)
    {
        $limit  =   '';
        $order  =   '';
        extract($options);
        $this->queryStr = 'DELETE FROM '
            .$this->parseTable($table)
            .$this->parseWhere($condition)
            .$this->parseOrder($order)
            .$this->parseLimit($limit);
        return $this->execute($this->queryStr,$options,$returnSql);
    }

    /**
     +----------------------------------------------------------
     * 更新记录
     +----------------------------------------------------------
     * @access public
     +----------------------------------------------------------
     * @param mixed $data 数据
     * @param array $options  更新参数
     +----------------------------------------------------------
     * @return false | integer
     +----------------------------------------------------------
     */
    public function update($data,$options=array(),$returnSql=false)
    {
        $limit  =   0;
        $order  =   '';
        $lock    =   false;
        extract($options);
        $this->queryStr = 'UPDATE '
            .$this->parseTable($table)
            .$this->parseSets($data)
            .$this->parseWhere($condition)
            .$this->parseOrder($order)
            .$this->parseLimit($limit);
        return $this->execute($this->queryStr,$options,$returnSql);
    }

    /**
     +----------------------------------------------------------
     * 保存某个字段的值
     +----------------------------------------------------------
     * @access public
     +----------------------------------------------------------
     * @param string $field 要保存的字段名
     * @param string $value  字段值
     * @param string $table  数据表
     * @param string $where 保存条件
     +----------------------------------------------------------
     * @return void
     +----------------------------------------------------------
     */
    public function setField($field,$value,$options=array(),$returnSql=false) {
        extract($options);
        $this->queryStr	=	'UPDATE '.$this->parseTable($table).' SET ';
        if(strpos($field,',')) {
            $field =  explode(',',$field);
        }
        if(is_array($field)) {
            $count   =  count($field);
            for($i=0;$i<$count;$i++) {
                $this->queryStr	.= $this->addSpecialChar($field[$i]).'='.$this->fieldFormat($value[$i]).',';
            }
        }else{
            $this->queryStr	.= $this->addSpecialChar($field).'='.$this->fieldFormat($value).',';
		}
		$this->queryStr	=	substr($this->queryStr,0,-1).$this->parseWhere($condition);
		return $this->execute($this->queryStr,$options,$returnSql);
    }

    /**
     +----------------------------------------------------------
     * 增加某个字段的值
     +----------------------------------------------------------
     * @access public
     +----------------------------------------------------------
     * @param string $field 要保存的字段名
     * @param string $table  数据表
     * @param string $where 保存条件
     * @param integer $step
     +----------------------------------------------------------
     * @return void
     +----------------------------------------------------------
     */
    public function setInc($field,$options=array(),$step=1,$returnSql=false) {
        return $this->setField($field,'('.$field.'+'.$step.')',$options,$returnSql);
    }

    /**
     +----------------------------------------------------------
     * 减少某个字段的值
     +----------------------------------------------------------
     * @access public
     +----------------------------------------------------------
     * @param string $field 要保存的字段名
     * @param string $table  数据表
     * @param string $where 保存条件
     * @param integer $step
     +----------------------------------------------------------
     * @return void
     +----------------------------------------------------------
     */
    public function setDec($field,$options=array(),$step=1,$returnSql=false) {
        return $this->setField($field,'('.$field.'-'.$step.')',$options,$returnSql);
    }

    /**
     +----------------------------------------------------------
     * 查询次数更新或者查询
     +----------------------------------------------------------
     * @access public
     +----------------------------------------------------------
     * @param mixed $times
     +----------------------------------------------------------
     * @return void
     +----------------------------------------------------------
     */
    public function Q($times='') {
        static $_times = 0;
        if(empty($times)) {
            return $_times;
        }else{
            $_times++;
            // 记录开始执行时间
            $this->beginTime = microtime(TRUE);
        }
    }

    /**
     +----------------------------------------------------------
     * 写入次数更新或者查询
     +----------------------------------------------------------
     * @access public
     +----------------------------------------------------------
     * @param mixed $times
     +----------------------------------------------------------
     * @return void
     +----------------------------------------------------------
     */
    public function W($times='') {
        static $_times = 0;
        if(empty($times)) {
            return $_times;
        }else{
            $_times++;
            // 记录开始执行时间
            $this->beginTime = microtime(TRUE);
        }
    }

    /**
     +----------------------------------------------------------
     * 获取最近一次查询的sql语句
     +----------------------------------------------------------
     * @access public
     +----------------------------------------------------------
     * @return string
     +----------------------------------------------------------
     */
    public function getLastSql() {
        return $this->queryStr;
    }

    /**
     +----------------------------------------------------------
     * 获取最近一次写入的主键值
     +----------------------------------------------------------
     * @access public
     +----------------------------------------------------------
     * @return string
     +----------------------------------------------------------
     */
    public function getLastInsID() {
        return $this->lastInsID;
    }

    /**
     +----------------------------------------------------------
     * 获取当前数据库类型
     +----------------------------------------------------------
     * @access public
     +----------------------------------------------------------
     * @return string
     +----------------------------------------------------------
     */
    public function getDbType() {
        return $this->dbType;
    }
}//类定义结束
?>